package io.github.harmonly.skyblock.data;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import io.github.harmonly.skyblock.game.scoreboard.Sidebar;
import io.github.harmonly.skyblock.manager.WorldManager;
import io.github.harmonly.skyblock.type.Rank;
import io.github.harmonly.skyblock.util.JavaUtil;
import io.github.harmonly.skyblock.util.StableObject;
import io.github.harmonly.skyblock.util.Utilities;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Sound;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.scoreboard.Criteria;
import org.bukkit.scoreboard.DisplaySlot;
import org.bukkit.scoreboard.Objective;
import org.bukkit.scoreboard.Scoreboard;
import org.bukkit.util.Vector;

import java.util.List;
import java.util.Random;
import java.util.UUID;

/**
 * Represents a player profile containing data managed using StableObject.
 */
public class ProfileData extends StableObject {

    private final PlayerData playerData;
    private final Player player;
    private final StableObject playingData;
    private final String MEMBER_KEY;

    // enabled on joining skyblock
    private Sidebar sidebar;

    public ProfileData(JsonElement raw, PlayerData playerData) {
        super(raw);
        this.playerData = playerData;
        player = playerData.getPlayer();
        playingData = new StableObject(new JsonObject());
        MEMBER_KEY = "members." + Utilities.simplifiedUuid(player.getUniqueId()) + ".";
    }

    public void init() {
        if (!hasProperty("profile_id")) {
            String profileId = UUID.randomUUID().toString();
            addProperty("profile_id", profileId);

            List<String> list = List.of("Apple", "Banana", "Blueberry", "Coconut", "Cucumber",
                    "Grapes", "Kiwi", "Lemon", "Lime", "Mango",
                    "Orange", "Papaya", "Peach", "Pear", "Pineapple",
                    "Pomegranate", "Raspberry", "Strawberry", "Tomato", "Watermelon",
                    "Zucchini");
            String cuteName = list.get(new Random().nextInt(list.size()));
            addProperty("cute_name", cuteName);

            String key = "stats.SkyBlock.profiles." + Utilities.simplifiedUuid(profileId) + ".";
            playerData.addProperty(key + "profile_id", profileId);
            playerData.addProperty(key + "cute_name", cuteName);
        }
        if (!hasProperty("create_at")) {
            addProperty("create_at", System.currentTimeMillis());
        }
        if (!hasProperty("members")) {
            addProperty(MEMBER_KEY + "player_id", player.getUniqueId().toString());

            addProperty(MEMBER_KEY + "leveling.completions", new JsonObject());
            addProperty(MEMBER_KEY + "leveling.completed_tasks", new JsonArray());
            addProperty(MEMBER_KEY + "leveling.experience", 0);
        }
        if (!hasProperty(MEMBER_KEY + "profile")) {
            addProperty(MEMBER_KEY + "profile.first_join", System.currentTimeMillis());
            addProperty(MEMBER_KEY + "profile.bank_account", 0.0);
        }
        // select profile
        playerData.selectProfile(getStringProperty("profile_id", "IMPOSSIBLE!!!"));
    }

    public void save() {
        if (sidebar != null) {
            sidebar.disable();
        }
        JavaUtil.writeJson(getRaw(), "data/profile/" + getProfileId() + ".json");
        Bukkit.unloadWorld("./skyblock/islands/" + getProfileId(), true);
    }

    public void updatePrefix() {
        String prefix = "§8[§7" + getIntProperty(MEMBER_KEY + "leveling.experience", 0) / 100 + "§8] ";
        Rank rank = Rank.getRank(playerData.getHighestRank());
        playerData.setDisplay(prefix, rank.getColor(), "");
    }

    public String getProfileId() {
        return getStringProperty("profile_id", "null");
    }

    public void setLastArea(String area) {
        addProperty(MEMBER_KEY + "last_area", area);
    }

    public String getLastArea() {
        return getStringProperty(MEMBER_KEY + "last_area", "island");
    }

    public boolean onIsland() {
        return player.getWorld().getName().contains("islands");
    }

    public boolean warp(String name) {
        boolean isToIsland = name.contains("island");
        String worldPath = isToIsland ?
                "./skyblock/islands/" + getProfileId() :
                "./skyblock/" + name;
        // load island
        if (isToIsland) {
            String islandPath = "./worlds/skyblock/islands/" + getProfileId();
            if (!JavaUtil.exist(islandPath)) {
                JavaUtil.unzipFile("./backup/skyblock/island.zip", islandPath);
            }
        }
        World world = WorldManager.load(worldPath);
        if (world == null) {
            player.sendMessage("§cCouldn't warp you! Try again later. §7(DYNAMIC_POOL_ERROR)");
            return false;
        }
        player.sendMessage(isToIsland && !onIsland() ?
                "§7Warping you to your SkyBlock island..." :
                "§7Warping..."
        );
        if (!world.getUID().equals(player.getWorld().getUID())) {
            player.sendMessage("§7Sending to world " + name + "...");
        }
        player.teleport(world.getSpawnLocation().add(new Vector(0.5, 0, 0.5)));
        setLastArea(name);
        return true;
    }

    public void playSkyBlock() {
        if (playerData.onSkyBlock()) {
            return;
        }
        player.sendMessage("§7Sending to world island...");
        player.sendMessage("", "§eWelcome to §aHypixel SkyBlock§e!", "");
        if (!warp(getLastArea())) {
            return;
        }
        player.setGameMode(GameMode.SURVIVAL);
        player.setInvulnerable(false);
        player.setFlying(false);
        player.setAllowFlight(false);

        // sidebar
        sidebar = new Sidebar(player);

        // below name
        Scoreboard scoreboard = player.getScoreboard();
        Objective objective = scoreboard.getObjective("BELOW_NAME");
        if (objective == null) {
            objective = player.getScoreboard().registerNewObjective("BELOW_NAME", Criteria.HEALTH, "§c❤");
        }
        objective.setDisplaySlot(DisplaySlot.BELOW_NAME);
    }

    public double getPurse() {
        return getDoubleProperty(MEMBER_KEY + "currencies.coin_purse", 0.0);
    }

    public void setPurse(double purse) {
        if (purse < 0) {
            return;
        }
        addProperty(MEMBER_KEY + "currencies.coin_purse", purse);
    }

    public void addPurse(double amount) {
        setPurse(getPurse() + amount);
        if (amount > 0) {
            playingData.addProperty("coin_purse_increased_amount", amount);
            player.playSound(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1, 1);
        }
    }

    public StableObject getPlayingData() {
        return playingData;
    }
}
